"""
Mock GSM Services

This module provides mock implementations of GSM services for testing extensions
without requiring a full GSM environment.
"""

from unittest.mock import Mock, MagicMock
from pathlib import Path
import tempfile
import json
import logging
from typing import Dict, List, Any, Optional

from ..base_extension import GSMServices


class MockDatabase:
    """Mock database service for testing."""
    
    def __init__(self):
        self.data: Dict[str, Any] = {}
        self.queries: List[str] = []
    
    def query(self, sql: str, params: tuple = None) -> List[Dict[str, Any]]:
        """Mock database query."""
        self.queries.append(sql)
        return []
    
    def execute(self, sql: str, params: tuple = None) -> int:
        """Mock database execute."""
        self.queries.append(sql)
        return 1
    
    def get_runs(self, limit: int = 10) -> List[Dict[str, Any]]:
        """Mock get runs."""
        return []
    
    def save_run(self, run_data: Dict[str, Any]) -> int:
        """Mock save run."""
        return 1


class MockLogManager:
    """Mock log manager service for testing."""
    
    def __init__(self):
        self.logs: List[str] = []
        self.log_files: Dict[str, Path] = {}
    
    def create_logger(self, name: str) -> logging.Logger:
        """Create a test logger."""
        logger = logging.getLogger(f"test.{name}")
        logger.setLevel(logging.DEBUG)
        
        # Add handler that captures log messages
        handler = MockLogHandler(self.logs)
        logger.addHandler(handler)
        
        return logger
    
    def create_log_file(self, name: str) -> Path:
        """Create a mock log file."""
        log_file = Path(tempfile.mktemp(suffix=".log"))
        self.log_files[name] = log_file
        return log_file


class MockLogHandler(logging.Handler):
    """Mock log handler that captures messages."""
    
    def __init__(self, logs: List[str]):
        super().__init__()
        self.logs = logs
    
    def emit(self, record: logging.LogRecord):
        """Capture log message."""
        message = self.format(record)
        self.logs.append(message)


class MockConfigManager:
    """Mock configuration manager for testing."""
    
    def __init__(self):
        self.configs: Dict[str, Dict[str, Any]] = {}
        self.schema_cache: Dict[str, Dict[str, Any]] = {}
    
    def get_extension_config(self, extension_name: str) -> Dict[str, Any]:
        """Get mock extension configuration."""
        return self.configs.get(extension_name, {
            'enabled': True,
            'priority': 10,
            'config': {}
        })
    
    def set_extension_config(self, extension_name: str, config: Dict[str, Any]):
        """Set mock extension configuration."""
        self.configs[extension_name] = config
    
    def load_config_file(self, file_path: Path) -> Dict[str, Any]:
        """Load mock configuration from file."""
        if file_path.exists():
            try:
                if file_path.suffix == '.json':
                    with open(file_path, 'r') as f:
                        return json.load(f)
                elif file_path.suffix in ['.yaml', '.yml']:
                    import yaml
                    with open(file_path, 'r') as f:
                        return yaml.safe_load(f)
            except:
                pass
        return {}
    
    def validate_config(self, config: Dict[str, Any], schema: Dict[str, Any]) -> List[str]:
        """Mock configuration validation."""
        # Simple mock validation - just check required fields
        errors = []
        
        if 'required' in schema:
            for field in schema['required']:
                if field not in config:
                    errors.append(f"Required field missing: {field}")
        
        return errors


class MockCacheManager:
    """Mock cache manager for testing."""
    
    def __init__(self):
        self.cache_data: Dict[str, Any] = {}
        self.cache_dirs: Dict[str, Path] = {}
        self.temp_dir = Path(tempfile.mkdtemp(prefix="gsm_mock_cache_"))
    
    def get_extension_cache_dir(self, extension_name: str) -> Path:
        """Get mock cache directory for extension."""
        if extension_name not in self.cache_dirs:
            cache_dir = self.temp_dir / extension_name
            cache_dir.mkdir(parents=True, exist_ok=True)
            self.cache_dirs[extension_name] = cache_dir
        
        return self.cache_dirs[extension_name]
    
    def get(self, key: str) -> Any:
        """Get cached value."""
        return self.cache_data.get(key)
    
    def set(self, key: str, value: Any, ttl: int = 3600):
        """Set cached value."""
        self.cache_data[key] = value
    
    def delete(self, key: str):
        """Delete cached value."""
        if key in self.cache_data:
            del self.cache_data[key]
    
    def clear(self):
        """Clear all cached values."""
        self.cache_data.clear()


class MockGSMServices(GSMServices):
    """Mock GSM services for testing extensions."""
    
    def __init__(self):
        self.mock_database = MockDatabase()
        self.mock_log_manager = MockLogManager()
        self.mock_config_manager = MockConfigManager()
        self.mock_cache_manager = MockCacheManager()
        
        super().__init__(
            database=self.mock_database,
            log_manager=self.mock_log_manager,
            config_manager=self.mock_config_manager,
            cache_manager=self.mock_cache_manager
        )
        
        self.logger_calls: List[str] = []
        self.config_calls: List[str] = []
        self.cache_calls: List[str] = []
    
    def get_logger(self, extension_name: str) -> logging.Logger:
        """Get mock logger for extension."""
        self.logger_calls.append(extension_name)
        return self.mock_log_manager.create_logger(extension_name)
    
    def get_config(self, extension_name: str) -> Dict[str, Any]:
        """Get mock configuration for extension."""
        self.config_calls.append(extension_name)
        return self.mock_config_manager.get_extension_config(extension_name)
    
    def get_cache_dir(self, extension_name: str) -> Path:
        """Get mock cache directory for extension."""
        self.cache_calls.append(extension_name)
        return self.mock_cache_manager.get_extension_cache_dir(extension_name)
    
    def setup_extension_config(self, extension_name: str, config: Dict[str, Any]):
        """Set up mock configuration for an extension."""
        self.mock_config_manager.set_extension_config(extension_name, config)
    
    def get_logged_messages(self) -> List[str]:
        """Get all logged messages."""
        return self.mock_log_manager.logs.copy()
    
    def get_database_queries(self) -> List[str]:
        """Get all database queries made."""
        return self.mock_database.queries.copy()
    
    def cleanup(self):
        """Clean up mock services."""
        # Clean up temporary directories
        if hasattr(self.mock_cache_manager, 'temp_dir') and self.mock_cache_manager.temp_dir.exists():
            import shutil
            shutil.rmtree(self.mock_cache_manager.temp_dir)
        
        # Clean up log files
        for log_file in self.mock_log_manager.log_files.values():
            if log_file.exists():
                log_file.unlink()


class MockExtensionComponent:
    """Base class for creating mock extension components."""
    
    def __init__(self, success: bool = True, error_message: str = None):
        self.success = success
        self.error_message = error_message
        self.call_log: List[tuple] = []
    
    def log_call(self, method_name: str, *args, **kwargs):
        """Log a method call."""
        self.call_log.append((method_name, args, kwargs))
    
    def get_call_history(self) -> List[tuple]:
        """Get history of method calls."""
        return self.call_log.copy()


class MockBuilder(MockExtensionComponent):
    """Mock builder for testing."""
    
    def check_dependencies(self):
        """Mock dependency checking."""
        from ..base_builder import BuildDependencyResult
        
        self.log_call('check_dependencies')
        
        result = BuildDependencyResult()
        result.success = self.success
        
        if not self.success:
            result.missing_dependencies = ['mock-dependency']
            result.error_message = self.error_message or "Mock dependency check failed"
        
        return result
    
    def build(self, config):
        """Mock build operation."""
        from ..base_builder import BuildResult
        
        self.log_call('build', config)
        
        result = BuildResult()
        result.success = self.success
        result.duration = 10.5
        
        if self.success:
            result.binary_path = Path('/tmp/mock_binary')
            result.build_log = "Mock build completed successfully"
        else:
            result.error_message = self.error_message or "Mock build failed"
        
        return result
    
    def clean(self, config):
        """Mock clean operation."""
        self.log_call('clean', config)
        return self.success
    
    def get_binary_path(self, config):
        """Mock binary path retrieval."""
        self.log_call('get_binary_path', config)
        return Path('/tmp/mock_binary') if self.success else None


class MockRunner(MockExtensionComponent):
    """Mock runner for testing."""
    
    def check_environment(self):
        """Mock environment checking."""
        from ..base_runner import EnvironmentResult
        
        self.log_call('check_environment')
        
        result = EnvironmentResult()
        result.valid = self.success
        
        if not self.success:
            result.issues = ['Mock environment issue']
        
        return result
    
    def run_solver(self, config):
        """Mock solver execution."""
        from ..base_runner import RunResult
        
        self.log_call('run_solver', config)
        
        result = RunResult()
        result.success = self.success
        result.duration = 5.2
        
        if self.success:
            result.stdout = "Mock solver output\nIterations: 100\nFinal residual: 1e-8"
            result.metrics = {'iterations': 100, 'final_residual': 1e-8}
        else:
            result.stderr = self.error_message or "Mock solver failed"
            result.exit_code = 1
        
        return result


class MockValidator(MockExtensionComponent):
    """Mock validator for testing."""
    
    def extract_metrics(self, run_result):
        """Mock metrics extraction."""
        self.log_call('extract_metrics', run_result)
        
        if self.success:
            return {
                'iterations': 100,
                'final_residual': 1e-8,
                'solve_time': 5.2,
                'converged': True
            }
        else:
            return {}
    
    def validate_result(self, run_result, config):
        """Mock result validation."""
        from ..base_validator import ValidationResult
        
        self.log_call('validate_result', run_result, config)
        
        result = ValidationResult()
        result.valid = self.success
        result.convergence_achieved = self.success
        
        if self.success:
            result.accuracy_metrics = {'final_residual': 1e-8}
            result.performance_metrics = {'solve_time': 5.2}
        else:
            result.errors = [self.error_message or "Mock validation failed"]
        
        return result
    
    def compare_results(self, result1, result2):
        """Mock result comparison."""
        from ..base_validator import ComparisonResult
        
        self.log_call('compare_results', result1, result2)
        
        result = ComparisonResult()
        result.similar = self.success
        result.similarity_score = 0.95 if self.success else 0.1
        
        if not self.success:
            result.differences = {'mock_difference': 'Large difference detected'}
        
        return result


def create_mock_extension(name: str = "mock-extension", 
                         success: bool = True,
                         builder_success: bool = None,
                         runner_success: bool = None,
                         validator_success: bool = None) -> Mock:
    """Create a mock extension for testing.
    
    Args:
        name (str): Extension name.
        success (bool): Overall success flag.
        builder_success (bool): Builder success (defaults to success).
        runner_success (bool): Runner success (defaults to success).
        validator_success (bool): Validator success (defaults to success).
        
    Returns:
        Mock: Mock extension object.
    """
    extension = Mock()
    
    # Set default success values
    if builder_success is None:
        builder_success = success
    if runner_success is None:
        runner_success = success
    if validator_success is None:
        validator_success = success
    
    # Basic properties
    extension.name = name
    extension.version = "1.0.0"
    extension.supported_frameworks = ["mock-framework"]
    extension.supported_solvers = ["mock-gcr", "mock-gmres"]
    extension.description = "Mock extension for testing"
    extension.author = "Test Author"
    extension.dependencies = {}
    
    # Mock components
    extension.get_builder.return_value = MockBuilder(builder_success)
    extension.get_runner.return_value = MockRunner(runner_success)
    extension.get_validator.return_value = MockValidator(validator_success)
    
    # Mock methods
    extension.get_config_schema.return_value = {
        "type": "object",
        "properties": {
            "test_config": {"type": "string"}
        }
    }
    
    extension.can_handle_config.return_value = True
    extension.initialize.return_value = success
    extension.cleanup.return_value = success
    
    # Mock metadata
    from ..base_extension import ExtensionMetadata
    extension.get_metadata.return_value = ExtensionMetadata(
        name=name,
        version="1.0.0",
        description="Mock extension for testing",
        supported_frameworks=["mock-framework"],
        supported_solvers=["mock-gcr", "mock-gmres"]
    )
    
    return extension